{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "B\n"
     ]
    }
   ],
   "source": [
    "#knn算法，机器学习实战源代码\n",
    "\n",
    "import numpy as np\n",
    "import operator\n",
    "\n",
    "#创建简单的数据用例x，y\n",
    "def createDataSet():\n",
    "    group = np.array([[1.0,1.1],[1.0,1.0],[0,0],[0,0.1]])\n",
    "    labels = ['A','A','B','B']\n",
    "    return group, labels\n",
    "\n",
    "#knn算法实现\n",
    "def classify0(inX, dataSet, labels, k):\n",
    "    dataSetSize = dataSet.shape[0]\n",
    "    diffMat = np.tile(inX, (dataSetSize,1)) - dataSet  #tile()用于扩展矩阵\n",
    "    sqDiffMat = diffMat**2\n",
    "    sqDistances = sqDiffMat.sum(axis=1)\n",
    "    distances = sqDistances**0.5 #求得距离\n",
    "    sortedDistIndicies = distances.argsort()  #返回排序的下标，从小到大   \n",
    "    classCount={}          \n",
    "    for i in range(k):\n",
    "        voteIlabel = labels[sortedDistIndicies[i]]\n",
    "        classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1 #用字典计数\n",
    "    sortedClassCount = sorted(classCount.iteritems(), key=operator.itemgetter(1), reverse=True)\n",
    "    #对字典排序，基于值，从大到小(逆序，reverse=True)\n",
    "    return sortedClassCount[0][0]\n",
    "\n",
    "#测试一下\n",
    "\n",
    "group,labels=createDataSet()\n",
    "\n",
    "pred=classify0([0,0],group,labels,3)\n",
    "\n",
    "print pred"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[  4.09200000e+04   8.32697600e+00   9.53952000e-01]\n [  1.44880000e+04   7.15346900e+00   1.67390400e+00]\n [  2.60520000e+04   1.44187100e+00   8.05124000e-01]\n [  7.51360000e+04   1.31473940e+01   4.28964000e-01]\n [  3.83440000e+04   1.66978800e+00   1.34296000e-01]]\n[3, 2, 1, 1, 1]\n"
     ]
    }
   ],
   "source": [
    "#导入数据集\n",
    "def file2matrix(filename):\n",
    "    fr = open(filename)\n",
    "    numberOfLines = len(fr.readlines())         #get the number of lines in the file\n",
    "    returnMat = np.zeros((numberOfLines,3))        #prepare matrix to return\n",
    "    classLabelVector = []                       #prepare labels return   \n",
    "    fr = open(filename)\n",
    "    index = 0\n",
    "    for line in fr.readlines():\n",
    "        line = line.strip()\n",
    "        listFromLine = line.split('\\t')\n",
    "        returnMat[index,:] = listFromLine[0:3]\n",
    "        classLabelVector.append(int(listFromLine[-1]))\n",
    "        index += 1\n",
    "    return returnMat,classLabelVector\n",
    "\n",
    "#导入数据\n",
    "datingDataMat,datingLabels = file2matrix(\"k-Nearest Neighbor/datingTestSet2.txt\")\n",
    "print datingDataMat[0:5]\n",
    "print datingLabels[0:5]\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\nz8fo0aNx8sknY9KkSXj22WfbcppxLF26FCNGjEBpaSmmTp2KHTt2tPWUDAwMAqLz1xrqJDjjjDPi\nwr+mpgYXXXQRjjvuOEyd2rYs2+jRo7F582bk5eXh/vvvx49+9CM8/vjjbTonAwODYOgyFsGaNUBJ\nCRAK8Z9r1qQ+5pdffonzzjsPZWVlGDlyJB5//HGUlJTgxz/+McLhMMaNG4e33noL06ZNw1e/+tV4\nZu/hw4cxdepUjBkzBqNGjcKf/xwscCocDmPRokW47777AHDr4ayzzoqvynfu3AkAePLJJzFy5EiU\nlZVh0qRJAICWlhYsWLAA48ePR2lpKVauXAkA2Lt3LyZNmoRwOIyRI0fitdde8zWXM888M15479RT\nT8WuXbsCPYuBgUE7ABG1+23s2LGk4t1330045oTVq4ny8oh4Vhnf8vL48VTwhz/8gf7jP/4jvh+J\nRKi4uJh+9atfERHR3LlzadSoUXTw4EH67LPPqH///kRE1NTURA0NDUREtH//fvrqV79K0WiUiIh6\n9OhBRESffPIJff3rXycioqqqKjrvvPNs9966dSudcsopREQ0ffp0evjhh4mI6IEHHqALL7yQiIhG\njhxJu3btIiKiAwcOEBHRypUr6c477yQiosbGRho7diz985//pLvuuov++7//m4iImpub6eDBg0RE\ndNlll1FZWVnC9sgjjyS8j5tuuik+toog35eBgUF6AGAz+ZCxXYIauu024MgR+7EjR/jxGTOSH3fU\nqFG4+eab8V//9V+YPn06zjjjDABWSepRo0bh8OHD6NWrF3r16oXu3bsjEomgR48euPXWW/Hqq68i\nFAph9+7d2LdvH4qKinzfm6TSIBs3bow3vbnyyivxox/9CADwjW98A1dddRUuu+wyfPvb3wYAvPji\ni3j77bfjjXMaGhqwfft2jB8/Htdccw2amppw0UUXIRwOA4Bvmmf16tXYvHkz1q9f7/sZDAwM2ge6\nhCKIMSW+j/vFSSedhLfeegvPP/88fvKTn8T5elFeOhQK2UpNh0IhNDc3Y82aNdi/fz+2bNmCnJwc\nlJSUoLGxMdC9t27d6lm759e//jU2bdqE5557DmPHjsWWLVtARLj33nsxbdq0hPNfffVVPPfcc7jq\nqqswf/58zJw5E5dffrmt+5qA+BzgfQ+WLFmC9evX257XwMCgY6BLKIIhQwBdMEuqJYz27NmDPn36\n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\nx3GcxPkfx4Jylljft1wAAAAASUVORK5CYII=\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x6455400>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "#可视化数据集合\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "def plot(x,y):\n",
    "    label1 = np.where(y == 1)[0]\n",
    "    plt.scatter(x[label1,0],x[label1,1],marker='x',color = 'r',label = 'didnt like=1')\n",
    "    label2 = np.where(y == 2)[0]\n",
    "    plt.scatter(x[label2,0],x[label2,1],marker='o',color = 'b',label = 'smallDoses=2')\n",
    "    label3 = np.where(y == 3)[0]\n",
    "    plt.scatter(x[label3,0],x[label3,1],marker='.',color = 'y',label = 'largeDoses=3')\n",
    "    plt.xlabel('pilot distance')\n",
    "    plt.ylabel('game time')\n",
    "    plt.legend(loc = 'upper left')\n",
    "    plt.show()\n",
    "    \n",
    "plot(datingDataMat,np.array(datingLabels).reshape(-1,1)) \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "the total error rate is: 0.050000\n5.0\n"
     ]
    }
   ],
   "source": [
    "#数值归一化\n",
    "\n",
    "def autoNorm(dataSet): \n",
    "    minVals = dataSet.min(0)\n",
    "    maxVals = dataSet.max(0)\n",
    "    ranges = maxVals - minVals\n",
    "    normDataSet = np.zeros(np.shape(dataSet))\n",
    "    m = dataSet.shape[0]\n",
    "    normDataSet = dataSet - np.tile(minVals, (m,1))\n",
    "    normDataSet = normDataSet/np.tile(ranges, (m,1))   #element wise divide\n",
    "    return normDataSet, ranges, minVals\n",
    "\n",
    "def datingClassTest():\n",
    "    hoRatio = 0.10      #hold out 10%,留作test集合\n",
    "    datingDataMat,datingLabels = file2matrix('k-Nearest Neighbor/datingTestSet2.txt')       #load data setfrom file\n",
    "    normMat, ranges, minVals = autoNorm(datingDataMat)\n",
    "    m = normMat.shape[0]\n",
    "    numTestVecs = int(m*hoRatio) #前面的numTestVecs作为测试集，后面的作为训练集\n",
    "    errorCount = 0.0\n",
    "    for i in range(numTestVecs):\n",
    "        classifierResult = classify0(normMat[i,:],normMat[numTestVecs:m,:] \n",
    "                                     ,datingLabels[numTestVecs:m],3)\n",
    "        #print \"the classifier came back with: %d, the real answer is: %d\" % (classifierResult, datingLabels[i])\n",
    "        if (classifierResult != datingLabels[i]): errorCount += 1.0\n",
    "    print \"the total error rate is: %f\" % (errorCount/float(numTestVecs))\n",
    "    print errorCount\n",
    "\n",
    "datingClassTest()\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2\nyou will probablly like this person: small dose\n"
     ]
    }
   ],
   "source": [
    "\n",
    "result = [\"didnt like\",\"small dose\",\"large dose\"]\n",
    "input = np.array([[10000,10,0.5]])\n",
    "#一定记得使用训练集去autoNorm，并且同时作用于测试数据\n",
    "normMat, ranges, minVals = autoNorm(datingDataMat)\n",
    "\n",
    "pred = classify0((input-minVals)/ranges,normMat,datingLabels,3)\n",
    "print pred\n",
    "print \"you will probablly like this person:\",result[pred-1]\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\nthe total number of errors is: 11\n\nthe total error rate is: 0.011628\n"
     ]
    }
   ],
   "source": [
    "from os import listdir\n",
    "\n",
    "def img2vector(filename):\n",
    "    returnVect = np.zeros((1,1024))\n",
    "    fr = open(filename)\n",
    "    for i in range(32): #32*32----->1*1024\n",
    "        lineStr = fr.readline()\n",
    "        for j in range(32):\n",
    "            returnVect[0,32*i+j] = int(lineStr[j])\n",
    "    return returnVect\n",
    "\n",
    "def handwritingClassTest():\n",
    "    hwLabels = []\n",
    "    trainingFileList = listdir('k-Nearest Neighbor/trainingDigits')   #load the training set\n",
    "    m = len(trainingFileList)\n",
    "    trainingMat = np.zeros((m,1024))\n",
    "    for i in range(m):\n",
    "        fileNameStr = trainingFileList[i]\n",
    "        fileStr = fileNameStr.split('.')[0]     #take off .txt\n",
    "        classNumStr = int(fileStr.split('_')[0]) #获得y的类别\n",
    "        hwLabels.append(classNumStr)\n",
    "        trainingMat[i,:] = img2vector('k-Nearest Neighbor/trainingDigits/%s' % fileNameStr)\n",
    "    testFileList = listdir('k-Nearest Neighbor/testDigits')        #iterate through the test set\n",
    "    errorCount = 0.0\n",
    "    mTest = len(testFileList)\n",
    "    for i in range(mTest):\n",
    "        fileNameStr = testFileList[i]\n",
    "        fileStr = fileNameStr.split('.')[0]     #take off .txt\n",
    "        classNumStr = int(fileStr.split('_')[0])\n",
    "        vectorUnderTest = img2vector('k-Nearest Neighbor/testDigits/%s' % fileNameStr)\n",
    "        classifierResult = classify0(vectorUnderTest, trainingMat, hwLabels, 3) \n",
    "        #预测，不需要归一化，因为数值已经是0/1\n",
    "        #print \"the classifier came back with: %d, the real answer is: %d\" % (classifierResult, classNumStr)\n",
    "        if (classifierResult != classNumStr): errorCount += 1.0\n",
    "    print \"\\nthe total number of errors is: %d\" % errorCount\n",
    "    print \"\\nthe total error rate is: %f\" % (errorCount/float(mTest))\n",
    "    \n",
    "#测试一下\n",
    "handwritingClassTest()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "\n",
    "    \n"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 2",
   "language": "python",
   "name": "python2"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}
